CREATE OR REPLACE EDITIONABLE PACKAGE BODY "SCOTT"."PKG_MODEL_INDEX" is

  /*-------------------- 海量地向表MDL_STOCK_INDEX_MACD_G_C中插入数据 ---------------------*/
  procedure CAL_MDL_STOCK_INDEX_MACD_G_C as
    -- 表示STOCK_INDEX_CODE
    v_stock_index_code varchar2(100);
    -- 表示STOCK_INDEX_DATE
    v_stock_index_date date;
    -- 记录数量
    v_record_num number;
    -- 上一个120日均线
    v_last_ma120 number;
    -- 上一个250日均线
    v_last_ma250 number;
    -- 1表示120日和250日均线都单调递增，0表示120日和250日均线至少有一个是递减的
    v_120_250_increasing number;
    -- 表示两天记录中的第一天，用于判断MACD是否发生了金叉或死叉
    v_first_stock_index stock_index%rowtype;
    -- 表示两天记录中的第二天，用于判断MACD是否发生了金叉或死叉
    v_second_stock_index stock_index%rowtype;
    -- 作为临时变量，表示STOCK_INDEX_CODE,BUY_DATE,SELL_DATE,BUY_PRICE,SELL_PRICE,BUY_DIF,BUY_DEA,SELL_DIF,SELL_DEA
    v_temp_stock_index_code       varchar2(100);
    v_temp_stock_index_buy_date   date;
    v_temp_stock_index_sell_date  date;
    v_temp_stock_index_buy_price  number;
    v_temp_stock_index_sell_price number;
    v_temp_stock_index_buy_dif    number;
    v_temp_stock_index_buy_dea    number;
    v_temp_stock_index_sell_dif   number;
    v_temp_stock_index_sell_dea   number;
    -- 用来判断现在是否是dif>dea的阶段，从而可以判断死叉
    v_start_track_gold_cross_stage number;
    -- 用来表示金叉和死叉是否发现了
    v_gold_cross_found  number;
    v_death_cross_found number;
    -- 每只指数初始的accumulative_profit_loss值为100（表示百分之一百），之后代表上一次交易的累计盈亏百分比
    v_init_last_acc_profit_loss number;
    -- 表示字段PROFIT_LOSS的临时变量
    v_temp_profit_loss number;
    -- 用于获取所有的STOCK_INDEX_CODE
    cursor cur_all_stock_index_code is
      select distinct t.code_ from stock_index t;
    -- 用于根据STOCK_INDEX_CODE获取某一只指数的所有交易记录
    cursor cur_single_stock_index is
      select *
        from stock_index t
       where t.code_ = lower(v_stock_index_code)
            -- 下面这行是固定时间的，也可以删除
         and t.date_ between to_date('20110101', 'yyyy-mm-dd') and
             to_date('20221231', 'yyyy-mm-dd')
       order by t.date_ asc;
    -- 表示stock_index表的记录，用于判断120日均线是否单调递减
    cursor cur_120_stock_index is
      select *
        from (select *
                from stock_index t
               where t.ma120 is not null
                 and t.code_ = v_stock_index_code
                 and t.date_ < v_stock_index_date
               order by t.date_ desc)
       where rownum <= 40;
    -- 表示stock_index表的记录，用于判断250日均线是否单调递减
    cursor cur_250_stock_index is
      select *
        from (select *
                from stock_index t
               where t.ma250 is not null
                 and t.code_ = v_stock_index_code
                 and t.date_ < v_stock_index_date
               order by t.date_ desc)
       where rownum <= 40;
    -- 用于获取某一只指数两天的交易记录，用于判断MACD是否发生了金叉或死叉
    cursor cur_single_s_i_two_record is
      select *
        from (select *
                from stock_index t
               where t.date_ >= v_stock_index_date
                 and t.code_ = lower(v_stock_index_code)
                    -- 下面这行是固定时间的，也可以删除
                 and t.date_ between to_date('20110101', 'yyyy-mm-dd') and
                     to_date('20221231', 'yyyy-mm-dd')
               order by t.date_ asc)
       where rownum <= 2;
  begin
    for i in cur_all_stock_index_code loop
      v_stock_index_code             := lower(i.code_);
      v_init_last_acc_profit_loss    := 100;
      v_start_track_gold_cross_stage := 0;
    
      for j in cur_single_stock_index loop
        v_stock_index_date   := j.date_;
        v_record_num         := null;
        v_last_ma120         := null;
        v_last_ma250         := null;
        v_120_250_increasing := 1;
      
        -- 判断120日均线是否单调递减
        select count(*)
          into v_record_num
          from stock_index t
         where t.ma120 is not null
           and t.code_ = v_stock_index_code
           and t.date_ <= v_stock_index_date;
        if v_record_num < 40 then
          continue;
        end if;
        for y in cur_120_stock_index loop
          if v_last_ma120 is null then
            v_last_ma120 := y.ma120;
            continue;
          end if;
          if v_last_ma120 < y.ma120 then
            v_120_250_increasing := 0;
            exit;
          end if;
          v_last_ma120 := y.ma120;
        end loop;
      
        -- 判断250日均线是否单调递减
        select count(*)
          into v_record_num
          from stock_index t
         where t.ma250 is not null
           and t.code_ = v_stock_index_code
           and t.date_ <= v_stock_index_date;
        if v_record_num < 40 then
          continue;
        end if;
        for y in cur_250_stock_index loop
          if v_last_ma250 is null then
            v_last_ma250 := y.ma250;
            continue;
          end if;
          if v_last_ma250 < y.ma250 then
            v_120_250_increasing := 0;
            exit;
          end if;
          v_last_ma250 := y.ma250;
        end loop;
      
        -- 如果120日和250日均线有一个是单调递减，则跳过。但是如果之前已经买入，则不跳过
        if v_120_250_increasing = 0 and v_start_track_gold_cross_stage = 0 then
          continue;
        end if;
      
        -- 如果最早的数据是dif>dea，那么接下来只有可能先出现死叉，所以要判断：j.dif<j.dea，也就是说如果第一段数据是dif>dea，则将其忽略
        -- 之后在确认了金叉后，需要确认死叉，所以引入了表示变量v_start_track_gold_cross_stage，当其为1时，表示接下来只可能出现死叉
        if j.dif < j.dea or
           (j.dif > j.dea and v_start_track_gold_cross_stage = 1) then
          -- 分别将两天的记录赋给相应的变量
          for x in cur_single_s_i_two_record loop
            if cur_single_s_i_two_record%rowcount = 1 then
              v_first_stock_index := x;
            elsif cur_single_s_i_two_record%rowcount = 2 then
              v_second_stock_index := x;
            end if;
          end loop;
          -- 如果出现了金叉，给临时变量赋值
          if v_first_stock_index.dif < v_first_stock_index.dea and
             v_second_stock_index.dif > v_second_stock_index.dea and
             v_start_track_gold_cross_stage = 0 then
            v_temp_stock_index_code      := v_second_stock_index.code_;
            v_temp_stock_index_buy_date  := v_second_stock_index.date_;
            v_temp_stock_index_buy_price := v_second_stock_index.close_price;
            v_temp_stock_index_buy_dif   := v_second_stock_index.dif;
            v_temp_stock_index_buy_dea   := v_second_stock_index.dea;
            v_gold_cross_found           := 1;
            -- 当金叉发生后，只可能发生死叉，因此要将v_start_track_gold_cross_stage设置为1
            v_start_track_gold_cross_stage := 1;
          
            dbms_output.put_line('gold cross   ' || j.date_);
          end if;
          -- 如果出现了死叉，给临时变量赋值
          if v_first_stock_index.dif > v_first_stock_index.dea and
             v_second_stock_index.dif < v_second_stock_index.dea and
             v_start_track_gold_cross_stage = 1 then
            v_temp_stock_index_sell_date  := v_second_stock_index.date_;
            v_temp_stock_index_sell_price := v_second_stock_index.close_price;
            v_temp_stock_index_sell_dif   := v_second_stock_index.dif;
            v_temp_stock_index_sell_dea   := v_second_stock_index.dea;
            v_death_cross_found           := 1;
            -- 当死叉发生后，只可能发生金叉，因此要将v_start_track_gold_cross_stage设置为0
            v_start_track_gold_cross_stage := 0;
          
            dbms_output.put_line('death cross   ' || j.date_);
          end if;
          -- 插入数据。要求这只指数在开始时间和结束时间内没有停牌或除权的情况
          if v_gold_cross_found = 1 and v_death_cross_found = 1 and
             v_temp_stock_index_buy_date is not null and
             v_temp_stock_index_sell_date is not null and
             v_temp_stock_index_code is not null then
            v_temp_profit_loss          := round((v_temp_stock_index_sell_price -
                                                 v_temp_stock_index_buy_price) /
                                                 v_temp_stock_index_buy_price,
                                                 4) * 100;
            v_init_last_acc_profit_loss := v_init_last_acc_profit_loss *
                                           (1 + v_temp_profit_loss / 100);
          
            insert into MDL_STOCK_INDEX_MACD_G_C
              (buy_date,
               sell_date,
               buy_price,
               sell_price,
               profit_loss,
               stock_index_code,
               accumulative_profit_loss,
               buy_dif,
               buy_dea,
               sell_dif,
               sell_dea,
               type_)
            values
              (v_temp_stock_index_buy_date,
               v_temp_stock_index_sell_date,
               v_temp_stock_index_buy_price,
               v_temp_stock_index_sell_price,
               v_temp_profit_loss,
               v_temp_stock_index_code,
               v_init_last_acc_profit_loss,
               v_temp_stock_index_buy_dif,
               v_temp_stock_index_buy_dea,
               v_temp_stock_index_sell_dif,
               v_temp_stock_index_sell_dea,
               6);
          
            v_gold_cross_found  := 0;
            v_death_cross_found := 0;
          end if;
        end if;
      end loop;
    end loop;
    commit;
  end CAL_MDL_STOCK_INDEX_MACD_G_C;

  /*------------------- 海量地向表MDL_STOCK_INDEX_C_P_MA5_G_C中插入数据 --------------------*/
  procedure CAL_MDL_STOCK_INDEX_CP_MA5_GC as
    -- 表示CODE_
    v_stock_index_code varchar2(100);
    -- 表示STOCK_INDEX_DATE
    v_stock_index_date date;
    -- 记录数量
    v_record_num number;
    -- 上一个120日均线
    v_last_ma120 number;
    -- 上一个250日均线
    v_last_ma250 number;
    -- 1表示120日和250日均线都单调递增，0表示120日和250日均线至少有一个是递减的
    v_120_250_increasing number;
    -- 作为临时变量，表示STOCK_INDEX_CODE,BUY_DATE,SELL_DATE,BUY_PRICE,SELL_PRICE,BUY_MA5,SELL_MA5
    v_temp_stock_index_code       varchar2(100);
    v_temp_stock_index_buy_date   date;
    v_temp_stock_index_sell_date  date;
    v_temp_stock_index_buy_price  number;
    v_temp_stock_index_sell_price number;
    v_temp_stock_index_buy_ma5    number;
    v_temp_stock_index_sell_ma5   number;
    -- 1表示close_price>ma5的阶段，2表示close_price<=ma5的阶段
    v_start_track_gold_cross_stage number;
    -- 每只指数初始的accumulative_profit_loss值为100（表示百分之一百），之后代表上一次交易的累计盈亏百分比
    v_init_last_acc_profit_loss number;
    -- 表示字段PROFIT_LOSS的临时变量
    v_temp_profit_loss number;
    -- 用于获取所有的CODE_
    cursor cur_all_stock_index_code is
      select distinct t.code_ from stock_index t;
    -- 用于根据CODE_获取某一只指数的所有交易记录
    cursor cur_single_stock_index is
      select *
        from stock_index t
       where t.code_ = v_stock_index_code
            -- 下面这行是固定时间的，也可以删除
         and t.date_ between to_date('20110101', 'yyyy-mm-dd') and
             to_date('20221231', 'yyyy-mm-dd')
       order by t.date_ asc;
    -- 表示stock_index表的记录，用于判断120日均线是否单调递减
    cursor cur_120_stock_index is
      select *
        from (select *
                from stock_index t
               where t.ma120 is not null
                 and t.code_ = v_stock_index_code
                 and t.date_ < v_stock_index_date
               order by t.date_ desc)
       where rownum <= 40;
    -- 表示stock_index表的记录，用于判断250日均线是否单调递减
    cursor cur_250_stock_index is
      select *
        from (select *
                from stock_index t
               where t.ma250 is not null
                 and t.code_ = v_stock_index_code
                 and t.date_ < v_stock_index_date
               order by t.date_ desc)
       where rownum <= 40;
  begin
    for i in cur_all_stock_index_code loop
      v_stock_index_code             := i.code_;
      v_init_last_acc_profit_loss    := 100;
      v_start_track_gold_cross_stage := 0;
    
      for j in cur_single_stock_index loop
        v_stock_index_date   := j.date_;
        v_record_num         := null;
        v_last_ma120         := null;
        v_last_ma250         := null;
        v_120_250_increasing := 1;
      
        -- 判断120日均线是否单调递减
        select count(*)
          into v_record_num
          from stock_index t
         where t.ma120 is not null
           and t.code_ = v_stock_index_code
           and t.date_ <= v_stock_index_date;
        if v_record_num < 40 then
          continue;
        end if;
        for y in cur_120_stock_index loop
          if v_last_ma120 is null then
            v_last_ma120 := y.ma120;
            continue;
          end if;
          if v_last_ma120 < y.ma120 then
            v_120_250_increasing := 0;
            exit;
          end if;
          v_last_ma120 := y.ma120;
        end loop;
      
        -- 判断250日均线是否单调递减
        select count(*)
          into v_record_num
          from stock_index t
         where t.ma250 is not null
           and t.code_ = v_stock_index_code
           and t.date_ <= v_stock_index_date;
        if v_record_num < 40 then
          continue;
        end if;
        for y in cur_250_stock_index loop
          if v_last_ma250 is null then
            v_last_ma250 := y.ma250;
            continue;
          end if;
          if v_last_ma250 < y.ma250 then
            v_120_250_increasing := 0;
            exit;
          end if;
          v_last_ma250 := y.ma250;
        end loop;
      
        -- 如果120日和250日均线有一个是单调递减，则跳过。但是如果之前已经买入，则不跳过
        if v_120_250_increasing = 0 and v_start_track_gold_cross_stage = 0 then
          continue;
        end if;
      
        if j.close_price > j.ma5 then
          if v_start_track_gold_cross_stage = 0 then
            -- 买入
            v_temp_stock_index_code        := j.code_;
            v_temp_stock_index_buy_date    := j.date_;
            v_temp_stock_index_buy_price   := j.close_price;
            v_temp_stock_index_buy_ma5     := j.ma5;
            v_start_track_gold_cross_stage := 1;
          else
            continue;
          end if;
        end if;
      
        if j.close_price <= j.ma5 then
          if v_start_track_gold_cross_stage = 1 then
            -- 卖出
            v_temp_stock_index_sell_date  := j.date_;
            v_temp_stock_index_sell_price := j.close_price;
            v_temp_stock_index_sell_ma5   := j.ma5;
            v_temp_profit_loss            := round((v_temp_stock_index_sell_price -
                                                   v_temp_stock_index_buy_price) /
                                                   v_temp_stock_index_buy_price,
                                                   4) * 100;
            v_init_last_acc_profit_loss   := v_init_last_acc_profit_loss *
                                             (1 + v_temp_profit_loss / 100);
            -- 插入记录
            insert into MDL_STOCK_INDEX_C_P_MA5_G_C
              (buy_date,
               sell_date,
               buy_price,
               sell_price,
               profit_loss,
               stock_index_code,
               accumulative_profit_loss,
               buy_ma5,
               sell_ma5,
               type_)
            values
              (v_temp_stock_index_buy_date,
               v_temp_stock_index_sell_date,
               v_temp_stock_index_buy_price,
               v_temp_stock_index_sell_price,
               v_temp_profit_loss,
               v_temp_stock_index_code,
               v_init_last_acc_profit_loss,
               v_temp_stock_index_buy_ma5,
               v_temp_stock_index_sell_ma5,
               6);
          
            -- 重置为0，表示还没有买入
            v_start_track_gold_cross_stage := 0;
          else
            continue;
          end if;
        end if;
      end loop;
    end loop;
    commit;
  end CAL_MDL_STOCK_INDEX_CP_MA5_GC;

  /*------------------- 海量地向表MDL_HEI_KIN_ASHI_DOWN_UP中插入数据 ---------------------*/
  procedure CAL_MDL_STOCK_INDEX_H_K_A_D_U as
    -- 表示CODE_
    v_stock_index_code varchar2(100);
    -- 表示STOCK_INDEX_DATE
    v_stock_index_date date;
    -- 记录数量
    v_record_num number;
    -- 上一个120日均线
    v_last_ma120 number;
    -- 上一个250日均线
    v_last_ma250 number;
    -- 1表示120日和250日均线都单调递增，0表示120日和250日均线至少有一个是递减的
    v_120_250_increasing number;
    -- 作为临时变量，表示CODE_,BUY_DATE,SELL_DATE,BUY_PRICE,SELL_PRICE
    v_temp_stock_index_code       varchar2(100);
    v_temp_stock_index_buy_date   date;
    v_temp_stock_index_sell_date  date;
    v_temp_stock_index_buy_price  number;
    v_temp_stock_index_sell_price number;
    -- 如果为1，则表示已经买入指数；如果为0，则表示还没有买入股票
    v_start_track_h_k_a_stage number;
    -- 每只指数初始的accumulative_profit_loss值为100（表示百分之一百），之后代表上一次交易的累计盈亏百分比
    v_init_last_acc_profit_loss number;
    -- 表示字段PROFIT_LOSS的临时变量
    v_temp_profit_loss number;
    -- 用于获取所有的CODE_
    cursor cur_all_stock_index_code is
      select distinct t.code_ from stock_index t;
    -- 用于根据CODE_获取某一只指数的所有交易记录
    cursor cur_single_stock_index is
      select *
        from stock_index t
       where t.code_ = v_stock_index_code
            -- 下面这行是固定时间的，也可以删除
         and t.date_ between to_date('20110101', 'yyyy-mm-dd') and
             to_date('20221231', 'yyyy-mm-dd')
       order by t.date_ asc;
    -- 表示stock_index表的记录，用于判断120日均线是否单调递减
    cursor cur_120_stock_index is
      select *
        from (select *
                from stock_index t
               where t.ma120 is not null
                 and t.code_ = v_stock_index_code
                 and t.date_ < v_stock_index_date
               order by t.date_ desc)
       where rownum <= 40;
    -- 表示stock_index表的记录，用于判断250日均线是否单调递减
    cursor cur_250_stock_index is
      select *
        from (select *
                from stock_index t
               where t.ma250 is not null
                 and t.code_ = v_stock_index_code
                 and t.date_ < v_stock_index_date
               order by t.date_ desc)
       where rownum <= 40;
  begin
    for i in cur_all_stock_index_code loop
      v_stock_index_code          := i.code_;
      v_init_last_acc_profit_loss := 100;
      v_start_track_h_k_a_stage   := 0;
    
      for j in cur_single_stock_index loop
        v_stock_index_date   := j.date_;
        v_record_num         := null;
        v_last_ma120         := null;
        v_last_ma250         := null;
        v_120_250_increasing := 1;
      
        -- 判断120日均线是否单调递减
        select count(*)
          into v_record_num
          from stock_index t
         where t.ma120 is not null
           and t.code_ = v_stock_index_code
           and t.date_ <= v_stock_index_date;
        if v_record_num < 40 then
          continue;
        end if;
        for y in cur_120_stock_index loop
          if v_last_ma120 is null then
            v_last_ma120 := y.ma120;
            continue;
          end if;
          if v_last_ma120 < y.ma120 then
            v_120_250_increasing := 0;
            exit;
          end if;
          v_last_ma120 := y.ma120;
        end loop;
      
        -- 判断250日均线是否单调递减
        select count(*)
          into v_record_num
          from stock_index t
         where t.ma250 is not null
           and t.code_ = v_stock_index_code
           and t.date_ <= v_stock_index_date;
        if v_record_num < 40 then
          continue;
        end if;
        for y in cur_250_stock_index loop
          if v_last_ma250 is null then
            v_last_ma250 := y.ma250;
            continue;
          end if;
          if v_last_ma250 < y.ma250 then
            v_120_250_increasing := 0;
            exit;
          end if;
          v_last_ma250 := y.ma250;
        end loop;
      
        -- 如果120日和250日均线有一个是单调递减，则跳过。但是如果之前已经买入，则不跳过
        if v_120_250_increasing = 0 and v_start_track_h_k_a_stage = 0 then
          continue;
        end if;
      
        if j.ha_index_close_price <= j.ha_index_open_price then
          -- 卖出
          if v_start_track_h_k_a_stage = 1 then
            v_start_track_h_k_a_stage     := 0;
            v_temp_stock_index_sell_date  := j.date_;
            v_temp_stock_index_sell_price := j.close_price;
            v_temp_profit_loss            := round((v_temp_stock_index_sell_price -
                                                   v_temp_stock_index_buy_price) /
                                                   v_temp_stock_index_buy_price,
                                                   4) * 100;
            v_init_last_acc_profit_loss   := v_init_last_acc_profit_loss *
                                             (1 + v_temp_profit_loss / 100);
          
            -- 插入记录
            insert into mdl_stock_index_h_k_a_down_up
              (stock_index_code,
               sell_date,
               sell_price,
               buy_date,
               buy_price,
               accumulative_profit_loss,
               profit_loss,
               type_)
            values
              (v_temp_stock_index_code,
               v_temp_stock_index_sell_date,
               v_temp_stock_index_sell_price,
               v_temp_stock_index_buy_date,
               v_temp_stock_index_buy_price,
               v_init_last_acc_profit_loss,
               v_temp_profit_loss,
               6);
          else
            continue;
          end if;
        end if;
      
        if j.ha_index_close_price > j.ha_index_open_price then
          -- 买入
          if v_start_track_h_k_a_stage != 1 then
            v_start_track_h_k_a_stage    := 1;
            v_temp_stock_index_buy_date  := j.date_;
            v_temp_stock_index_buy_price := j.close_price;
            v_temp_stock_index_code      := j.code_;
          end if;
        end if;
      end loop;
    end loop;
    commit;
  end CAL_MDL_STOCK_INDEX_H_K_A_D_U;

  /*---------------- 海量地向表MDL_STOCK_INDEX_KD_GOLD_CROSS中插入数据 -----------------*/
  procedure CAL_MDL_STOCK_INDEX_KD_G_C as
    -- 表示CODE_
    v_stock_index_code varchar2(100);
    -- 表示STOCK_INDEX_DATE
    v_stock_index_date date;
    -- 记录数量
    v_record_num number;
    -- 上一个120日均线
    v_last_ma120 number;
    -- 上一个250日均线
    v_last_ma250 number;
    -- 1表示120日和250日均线都单调递增，0表示120日和250日均线至少有一个是递减的
    v_120_250_increasing number;
    -- 作为临时变量，表示CODE_,BUY_DATE,SELL_DATE,BUY_PRICE,SELL_PRICE,K,D
    v_temp_stock_index_code       varchar2(100);
    v_temp_stock_index_buy_date   date;
    v_temp_stock_index_sell_date  date;
    v_temp_stock_index_buy_price  number;
    v_temp_stock_index_sell_price number;
    v_temp_stock_index_buy_k      number;
    v_temp_stock_index_sell_k     number;
    v_temp_stock_index_buy_d      number;
    v_temp_stock_index_sell_d     number;
    -- 如果为1，则表示已经买入指数了；如果为0，则表示还没有买入指数
    v_start_track_kd_g_c_stage number;
    -- 每只指数初始的accumulative_profit_loss值为100（表示百分之一百），之后代表上一次交易的累计盈亏百分比
    v_init_last_acc_profit_loss number;
    -- 表示字段PROFIT_LOSS的临时变量
    v_temp_profit_loss number;
    -- 用于获取所有的CODE_
    cursor cur_all_stock_index_code is
      select distinct t.code_ from stock_index t;
    -- 用于根据CODE_获取某一只指数的所有交易记录
    cursor cur_single_stock_index is
      select *
        from stock_index t
       where t.code_ = v_stock_index_code
            -- 下面这行是固定时间的，也可以删除
         and t.date_ between to_date('20110101', 'yyyy-mm-dd') and
             to_date('20221231', 'yyyy-mm-dd')
       order by t.date_ asc;
    -- 表示stock_index表的记录，用于判断120日均线是否单调递减
    cursor cur_120_stock_index is
      select *
        from (select *
                from stock_index t
               where t.ma120 is not null
                 and t.code_ = v_stock_index_code
                 and t.date_ < v_stock_index_date
               order by t.date_ desc)
       where rownum <= 40;
    -- 表示stock_index表的记录，用于判断250日均线是否单调递减
    cursor cur_250_stock_index is
      select *
        from (select *
                from stock_index t
               where t.ma250 is not null
                 and t.code_ = v_stock_index_code
                 and t.date_ < v_stock_index_date
               order by t.date_ desc)
       where rownum <= 40;
  begin
    for i in cur_all_stock_index_code loop
      v_stock_index_code          := i.code_;
      v_init_last_acc_profit_loss := 100;
      v_start_track_kd_g_c_stage  := 0;
    
      for j in cur_single_stock_index loop
        v_stock_index_date   := j.date_;
        v_record_num         := null;
        v_last_ma120         := null;
        v_last_ma250         := null;
        v_120_250_increasing := 1;
      
        -- 判断120日均线是否单调递减
        select count(*)
          into v_record_num
          from stock_index t
         where t.ma120 is not null
           and t.code_ = v_stock_index_code
           and t.date_ <= v_stock_index_date;
        if v_record_num < 40 then
          continue;
        end if;
        for y in cur_120_stock_index loop
          if v_last_ma120 is null then
            v_last_ma120 := y.ma120;
            continue;
          end if;
          if v_last_ma120 < y.ma120 then
            v_120_250_increasing := 0;
            exit;
          end if;
          v_last_ma120 := y.ma120;
        end loop;
      
        -- 判断250日均线是否单调递减
        select count(*)
          into v_record_num
          from stock_index t
         where t.ma250 is not null
           and t.code_ = v_stock_index_code
           and t.date_ <= v_stock_index_date;
        if v_record_num < 40 then
          continue;
        end if;
        for y in cur_250_stock_index loop
          if v_last_ma250 is null then
            v_last_ma250 := y.ma250;
            continue;
          end if;
          if v_last_ma250 < y.ma250 then
            v_120_250_increasing := 0;
            exit;
          end if;
          v_last_ma250 := y.ma250;
        end loop;
      
        -- 如果120日和250日均线有一个是单调递减，则跳过。但是如果之前已经买入，则不跳过
        if v_120_250_increasing = 0 and v_start_track_kd_g_c_stage = 0 then
          continue;
        end if;
      
        if j.k <= j.d then
          -- 卖出
          if v_start_track_kd_g_c_stage = 1 then
            v_start_track_kd_g_c_stage    := 0;
            v_temp_stock_index_sell_date  := j.date_;
            v_temp_stock_index_sell_price := j.close_price;
            v_temp_stock_index_sell_k     := j.k;
            v_temp_stock_index_sell_d     := j.d;
            v_temp_profit_loss            := round((v_temp_stock_index_sell_price -
                                                   v_temp_stock_index_buy_price) /
                                                   v_temp_stock_index_buy_price,
                                                   4) * 100;
            v_init_last_acc_profit_loss   := v_init_last_acc_profit_loss *
                                             (1 + v_temp_profit_loss / 100);
          
            -- 插入记录
            insert into mdl_stock_index_kd_gold_cross
              (stock_index_code,
               sell_date,
               sell_price,
               sell_k,
               sell_d,
               buy_date,
               buy_price,
               buy_k,
               buy_d,
               accumulative_profit_loss,
               profit_loss,
               type_)
            values
              (v_temp_stock_index_code,
               v_temp_stock_index_sell_date,
               v_temp_stock_index_sell_price,
               v_temp_stock_index_sell_k,
               v_temp_stock_index_sell_d,
               v_temp_stock_index_buy_date,
               v_temp_stock_index_buy_price,
               v_temp_stock_index_buy_k,
               v_temp_stock_index_buy_d,
               v_init_last_acc_profit_loss,
               v_temp_profit_loss,
               6);
          else
            continue;
          end if;
        end if;
      
        if j.k > j.d then
          -- 买入
          if v_start_track_kd_g_c_stage != 1 then
            v_start_track_kd_g_c_stage   := 1;
            v_temp_stock_index_buy_date  := j.date_;
            v_temp_stock_index_buy_price := j.close_price;
            v_temp_stock_index_buy_k     := j.k;
            v_temp_stock_index_buy_d     := j.d;
            v_temp_stock_index_code      := j.code_;
          end if;
        end if;
      end loop;
    end loop;
    commit;
  end CAL_MDL_STOCK_INDEX_KD_G_C;
end PKG_MODEL_INDEX;